package dst.ass3.aop.management;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

import dst.ass3.aop.IPluginExecutable;

/**
 * The template already denes a method annotation (Timeout), which has one Long parameter.
 * Users can use this annotation on IPluginExecutable.execute() methods to dene the \nor-
 * mal" maximum execution time of their plugins.
 * 
 * Have the aspect hook into each invocation of IPluginExecutable.execute() to keep track of the currently
 * running plugins and their start time. From the start time you can then derive the current execution
 * duration, e.g., by polling in regular intervals or using a timer task. If a plugin is detected that takes
 * longer than its maximum defined time, call this plugin's interrupted() method. You do not need
 * to take any further action (i.e., we can assume that the developer of the plugin actually terminates
 * the plugin if this callback is invoked). However, keep in mind that the interrupted() method can
 * itself take some time to execute, so do not block while the client is cleaning up. If no timeout is
 * defined for a plugin, you can assume that the plugin can run for as long as it needs to.
 */

@Aspect
public class ManagementAspect {

    private Timer timer = new Timer();
    private List<IPluginExecutable> recentlyActiveExecutables = Collections.synchronizedList(new ArrayList<IPluginExecutable>());

    //A join point is a point in the control flow of a program. In aspect-oriented programming a set of join points is called a pointcut. 
    //A join point is a specification of when, in the corresponding main program, the aspect code should be executed.
    //triggers when execution
    
    //call class where it calls
    //execute class in that it is executed
    
    //trigger when execute is called and 
    //Annotation (Timeout) is used in InterruptedPluginExecutable
    @Pointcut("execution(* dst.ass3.aop.IPluginExecutable.execute(..)) && @annotation(timeout)")
    void timeoutExecution(Timeout timeout) { }

    
    //before timeoutExecution is called
    @Before("timeoutExecution(timeout)")
    public void beforeTimeoutExecution(JoinPoint thisJoinPoint, Timeout timeout) {
        final IPluginExecutable activeExecution = (IPluginExecutable)thisJoinPoint.getTarget();  //activeExecution that runs

        recentlyActiveExecutables.add(activeExecution);  //add to active executable list

        try {
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    if (recentlyActiveExecutables.contains(activeExecution)) {   //if it is already 
                    	activeExecution.interrupted();					//interrupt execution
                    }
                }
            }, timeout.value());
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }

    //after timeoutExecution is called
    @After("timeoutExecution(timeout)")
    public void afterTimeoutExecution(JoinPoint thisJoinPoint, Timeout timeout) {
    	recentlyActiveExecutables.remove(thisJoinPoint.getTarget());  //remove it from active list
    }
}
